package cn.edu.lingnan.utils;

import java.time.Instant;

public class SnowflakeIdUtil {

    // 开始时间戳 (自定义一个较早的固定时间)
    private static final long START_TIMESTAMP = 1609459200000L; // 2021-01-01 00:00:00

    // 每部分的位数分配
    private static final long SEQUENCE_BITS = 12; // 序列号占用位数
    private static final long MACHINE_BITS = 5;  // 机器ID占用位数

    private static final long MAX_SEQUENCE = (1 << SEQUENCE_BITS) - 1; // 序列号最大值
    private static final long MAX_MACHINE_ID = (1 << MACHINE_BITS) - 1; // 机器ID最大值

    private static final long MACHINE_ID = 1; // 默认机器ID，可根据需要修改或外部注入

    private static long sequence = 0L;   // 当前序列号
    private static long lastTimestamp = -1L; // 上次生成ID的时间戳

    private SnowflakeIdUtil() {
        // 私有化构造方法，防止实例化
    }

    /**
     * 生成18位以6开头的唯一ID
     *
     * @return 18位唯一字符串ID
     */
    public static synchronized String nextId() {
        long currentTimestamp = getCurrentTimestamp();

        if (currentTimestamp < lastTimestamp) {
            throw new RuntimeException("Clock moved backwards. Refusing to generate id");
        }

        if (currentTimestamp == lastTimestamp) {
            // 同一毫秒内自增
            sequence = (sequence + 1) & MAX_SEQUENCE;
            if (sequence == 0) {
                // 序列号用尽，等待下一毫秒
                currentTimestamp = waitForNextMillis(currentTimestamp);
            }
        } else {
            // 不同毫秒，序列号置0
            sequence = 0L;
        }

        lastTimestamp = currentTimestamp;

        // 计算唯一ID
        long id = (currentTimestamp - START_TIMESTAMP) << (SEQUENCE_BITS + MACHINE_BITS)
                | (MACHINE_ID << SEQUENCE_BITS)
                | sequence;

        // 转换为18位以6开头的字符串
        return "6" + String.format("%017d", id);
    }

    // 等待下一毫秒
    private static long waitForNextMillis(long currentTimestamp) {
        while (currentTimestamp <= lastTimestamp) {
            currentTimestamp = getCurrentTimestamp();
        }
        return currentTimestamp;
    }

    // 获取当前时间戳
    private static long getCurrentTimestamp() {
        return Instant.now().toEpochMilli();
    }

    public static void main(String[] args) {
        // 测试生成ID
        for (int i = 0; i < 10; i++) {
            System.out.println(SnowflakeIdUtil.nextId());
        }
    }
}
